package top.zhaoyuliu.logbook.client.utils;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

import org.slf4j.helpers.MessageFormatter;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.ThrowableProxy;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import top.zhaoyuliu.logbook.client.builder.LbBuilder;
import top.zhaoyuliu.logbook.client.compent.AppenderCompent;

public class LogObejctUtil {

	public static LbBuilder getLogMessage(String trackId, final ILoggingEvent iLoggingEvent) {
		if (StrUtil.isBlank(trackId)) {
			trackId = UUID.randomUUID().toString();
		}
		List<String> level = AppenderCompent.level;
		if (CollectionUtil.isNotEmpty(AppenderCompent.level)) {
			if (!level.contains(iLoggingEvent.getLevel().levelStr)) {
				return null;
			}
		}
		String error = getThrowableContent(iLoggingEvent);
		StringBuffer buffer = new StringBuffer();
		if (ObjectUtil.isNotEmpty(iLoggingEvent.getCallerData())) {
			StackTraceElement atackTraceElement = iLoggingEvent.getCallerData()[0];
			String method = atackTraceElement.getMethodName();
			String line = String.valueOf(atackTraceElement.getLineNumber());
			buffer.append(method).append("<").append(atackTraceElement.getFileName()).append(":").append(line)
					.append(")");
		} else {
			buffer.append(iLoggingEvent.getThreadName());
		}
		LbBuilder builder = LbBuilder.builder().clzz(iLoggingEvent.getLoggerName())
				.content(iLoggingEvent.getFormattedMessage()).exception(error).methed(buffer.toString())
				.trackId(trackId).level(iLoggingEvent.getLevel().levelStr).build();
		return builder;
	}

	private static String getThrowableContent(ILoggingEvent logEvent) {
		if (Level.ERROR.equals(logEvent.getLevel())) {
			if (ObjectUtil.isNotNull(logEvent.getThrowableProxy())) {
				ThrowableProxy throwableProxy = (ThrowableProxy) logEvent.getThrowableProxy();
				String[] args = new String[] { logStackTrace(throwableProxy.getThrowable()).toString() };
				return error(logEvent.getMessage(), args);
			} else {
				Object[] args = logEvent.getArgumentArray();
				if (args != null) {
					for (int i = 0; i < args.length; i++) {
						if (args[i] instanceof Throwable) {
							args[i] = logStackTrace(args[i]);
						}
					}
					return error(logEvent.getMessage(), args);
				}
			}
		}
		return null;
	}

	private static String error(String content, Object[] args) {
		if (StrUtil.isNotBlank(content) && content.indexOf("{}") > -1) {
			return MessageFormatter.arrayFormat(content, args).getMessage();
		}
		return arrayFormat(content, args);
	}

	private static String arrayFormat(String content, Object[] args) {
		StringBuffer builder = new StringBuffer();
		builder.append(content);
		for (int i = 0; i < args.length; i++) {
			builder.append("\n").append(args[i]);
		}
		return builder.toString();
	}

	private static Object logStackTrace(Object obj) {
		if (obj instanceof Exception) {
			Exception eObj = (Exception) obj;
			StringWriter sw = null;
			PrintWriter pw = null;
			try {
				sw = new StringWriter();
				pw = new PrintWriter(sw);
				String exceptionStack = "\r\n";
				eObj.printStackTrace(pw);
				exceptionStack = sw.toString();
				return exceptionStack;
			} catch (Exception e) {
				e.printStackTrace();
				return obj;
			} finally {
				try {
					pw.close();
					sw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} else {
			return obj;
		}
	}

}
